December 09, 2020
동일한 환경에 있는 코드들을 실행 시, 필요한 환경정보들을 모아 컨텍스트를 구성하고, 이를 콜스택 (call stack)에 쌓았다가 가장 위에 쌓여있는 컨텍스트와 관련있는 코드들을 실행한다.아래 예시를 통해 실행컨텍스트가 어떻게 구성되는지 알아보자.
function func1() {
let a = 1
function fun2() {
console.log('함수 실행 컨텍스트2')
}
console.log('함수 실행 컨텍스트1')
func2()
}
console.log('글로벌 실행 컨텍스트')
func1()
스코프 체인이 연결된다.
식별자 정보가 저장 되며 , 컨텍스트 내부 전체를 순서대로 수집한다.✔️ Declarative Environment Record와 ✔️ Object Environment Record 그리고 ✔️ Global Environment Record 로 구성되어 있다.상위 레벨에서 정의된 모듈에 대한 바인딩을 저장한다.실행 컨텍스트의 객체 종류를 알아보았으니, 그에 따라서 실행 컨텍스트의 생성 과정을 더 자세히 알아보도록 하겠다.
실행 컨텍스트는 위에서도 알아봤듯이, 실행 가능한 코드(글로벌 / eval / 함수) 를 실행하기 위해 필요한 환경이다. 이 때 실행 가능한 코드가 실행될때 실행하기 위해 필요한 환경 (실행 컨텍스트) 는 두 가지 단계로 생성된다.
컴파일러는 실제 코드를 ‘실행(2단계)’ 하기 전에 코드를 두번 실행해준다.
두번 실행을 통해서 Variable Environiment 와 Lexical Environment가 생성된다. 생성된 Lexical Environment는 다음과 같은 일련의 과정을 거친다.
Environment Record를 초기화한다.
함수 호이스팅 : 코드 내부 함수 선언을 대상으로, 함수명이 Environment Record의 프로퍼티로 생성되고, 생성된 함수 객체가 해당 프로퍼티의 값으로 설정된다.변수 호이스팅 : 코드 내부 변수 선언을 대상으로, 변수명이 Environment Record의 프로퍼티로 생성되고, 값은 undefined가 할당된다.Outer Environment Reference
변수 호이스팅과 TDZ
TDZ (Temporal Dead Zone )
TDZ란 변수 선언문 전까지 해당 변수에 접근할 수 없는 공간을 위치한다. TDZ에서 해당 변수를 참조하면 undefined가 아니라 ReferenceError가 뜬다.
// this is TDZ // this is TDZ // console.log(foo) 결과 : ReferenceError let foo = 'bar' // No More TDZES6에 도입된 let과 const 는 var와 달리 TDZ가 생성되므로, 변수 선언 이전에는 참조 할 수 없다. 이는 마치 직관적으로 ’ 호이스팅 ‘을 막아놓은 것 처럼 보이지만, 실제적으로 호이스팅을 막은게 아니라 TDZ라는 개념을 추가한 것 뿐이다.
함수 선언식과 함수 표현식
- 함수 선언식은 함수 호이스팅으로 인해 함수 전체를 호이스팅하지만, 표현식은 변수 호이스팅으로 선언부만 호이스팅한다.
- 따라서 표현식은 함수 선언 이전에 함수를 호출하면 ’~ is not a function’ 이라는 에러를 띄운다.
Lexical Environment 중에서 Outer Environment Reference에 의해서 형성되는 스코프 체인에 대해 알아보도록 하겠다.
var greeting = 'hello!'
function greet() {
console.log(greeting) // 외부의 greeting 변수에 접근 할 수 있다.
}
greet() // "hello!";function greet() {
var greeting = 'hello!'
console.log(greeting)
}
greet() // "hello!"
console.log(greeting) // Reference Error
// 글로벌 스코프에서 함수 내에서 선언된 변수에 접근이 불가능함을 알 수 있다.{
let greeting = 'hello!'
var foo = 'bar'
}
console.log(foo) // "bar"
console.log(greeting) // Reference Error여러 스코프에서 동일한 식별자를 선언한 경우, 무조건 스코프 체니상에서 가장 먼저 발견된 식별자에만 접근 가능하다.
변수은닉화 : 함수 내부와 글로벌 공간에서 동일한 식별자를 선언했다면, 함수 내부에서는 오로지 내부에 선언된 변수에만 접근 가능Lexical Environment 가 생성될 때, Outer Environment Reference에 외부 스코프의 Lexical Environment를 참조한다.
클로저 : 외부 함수의 실행 컨텍스트가 스택에서 사라지더라도 Outer Environment Reference가 가리키는 외부 함수의 실행 환경은 소멸되지 않고 참조 가능하다.var name = 'voldMort'
function Outer() {
var name = 'Tom Mavolo Riddle'
function Inner() {
var name = 'You Know Who'
console.log(name) // "You Know Who"
}
Inner()
console.log(name) // "Tom Mavolo Riddle"
}
Outer()
console.log(name) // "voldMort"위의 예시는 name이라는 같은 식별자를 가진 변수를 1. 글로벌 스코프 2. outer 함수 스코프 3. inner 함수 스코프에서 각각 선언했다. 이를 통해서 각 스코프 내부에 선언된 name에만 접근 할 수 있음을 알 수 있다.
[Javascript] Execution Context와 Lexical Environment
What is the Temporal Dead Zone (TDZ) in JavaScript?